<?php

/**
 * Je stromem
 * @author Michal Hantl
 * @category core
 * @version 0.0.1
 */
 
class cTree {
	
	public $link;
	public $prefix;
	public $table;
	
	public $id_name="id";
    public $parent_id_name="parent_id";
	public $lft_name="lft";
    public $rgt_name="rgt";
	
	/** Kontruktor, zároveň spojuje strom s databází */
	function cTree(cCMS $cms)
	{
		$this->table = strToLower($this->prefix."standard_treeitem");
	  	$this->cms = $cms;
	}
	
	/** Vrací počet řádků */
	function getCount($where, $view) 
	{
		$count = $this->selectRaw($where, $view, "COUNT(*)");
		return $count[0][0]; 
	}

	/** Vrací počet řádky (alias) */
	function getRaw($where, $view=null, $select="*") 
	{
		 return $this->selectRaw($where, $view, $select); 
	} 

	/** Vrací počet řádky */
	function selectRaw($where, $view=null, $select="*")
	{
		$rows = array();
		
		//stránkování
		if ($view->paging!=null) 
		{
			$limit="LIMIT ".$view->paging;
			if ($view->page!=null) 
			{
				//pro stabilitu
				if ($view->page==0) $view->page=1;
				$limit.=" OFFSET ".($view->page-1)*$view->paging;
			}
		} else unset($view->paging);
		
		
		//viditelnost privátních
		if (is_numeric($aId = $this->cms->user->id) && $view->mode=="backend") {
			$visibility = "(visibility<>'private' OR author_id=".$aId.")";
		} else $visibility = "visibility<>'private'";
		
		//z frontendu nechceme vidět nepublikované
		if ($view->mode === "frontend") {
			$visibility.=" AND visibility='published'";
		}
		
		$r=$this->query($q = "SELECT ".$select." FROM `".$this->prefix."standard_treeitem` WHERE $visibility AND $where $limit");
		
		$this->cms->debugger->log($q, $this);
		
		while (@$row=mysql_fetch_array($r)) {
			$rows[]=$row;	
			$this->usedIds[$row['id']]=1;
		}
		return $rows;
	}	

	function getRoot() 
	{
		$root = $this->getNode("`parent_id` IS NULL ORDER BY `lft`");
		if ($root->lft!=1) 
		{
			//echo 'opravil bych to '.$root->id;
			
			$this->fixDB();
		}
		$this->usedIds[$root->id]=1;
		return $root;
	}
	
	function getPath($id) 
	{
		$row = $this->getRaw("id=".$id);
		$path = $this->getRaw("lft<=".$row[0]["lft"]." AND rgt>=".$row[0]["rgt"]." ORDER BY lft");
		$p = array();
		foreach ($path as $k=>$n) 
		{
			//ze začátku se párkrát stalo, že se insertnul špatný node, pro jistotu
			if ($n["string_id"]!="") {
				$p[]= $n;
				$this->usedIds[$n['id']]=1;
			}
		}			
		return $p;	
	}
	
	/* ================================================================= */
	/* --------------------- SELECTY CELÝCH NODEů  --------------------- */
	/* ================================================================= */
	
	/** Vrací celý jeden node*/	 
	function getNodeById($id, cView $view=null)
	{
		if (!is_numeric($id)) throw new cException('Id '.$id.' není číslo.');

		$this->usedIds[$id]=1;
		
		$r=$this->query($q = "SELECT * FROM `".$this->prefix."standard_treeitem` WHERE (visibility<>'private' OR author_id=".$this->cms->user->id.") AND ".$this->prefix."standard_treeitem.id = $id");
		$sxml = $this->mysqlFetchSXML($r);
			
		if ((string)$sxml[0]->standard_treeitem->group!="" && (string)$sxml[0]->standard_treeitem->type!="") 
		{
			$nodeClass = $this->cms->file->loadNode((string)$sxml[0]->standard_treeitem->group,(string)$sxml[0]->standard_treeitem->type);
			$node = new $nodeClass($this->cms);
			$node->setData($sxml[0]);
			return $node;
			
		} else throw new cException("Našel jsem ducha! jeho id je $id ");
	} 
	

	/**
	 * Vrátí přímo celé NODEy, výhodné pro perexy, přímo celé �l�nky
	 */
	function getNodes($where, cView $view = null) 
	{
		return $this->getWholeNodes(array('standard_treeitem'), $where, $view);
	} 

	function getNode($where, cView $view = null) 
	{
		$nodes = $this->getWholeNodes(array('standard_treeitem'), $where. " LIMIT 1", $view);
		return $nodes[0];
	} 

	 
	function getWholeNodes($tables, $where, cView $view = null)
	{
		$nodes=array();
		$sxmls = $this->getSXML($tables, $where, $view);
		
		foreach ($sxmls as $el) 
		{
			// pro cache
			$id = $el->xpath($tables[0].'/id');
			$this->usedIds[(string)$id[0]]=1;
			
			$group = $el->xpath($tables[0].'/group');
			$type = $el->xpath($tables[0].'/type');

			$nodeClass = $this->cms->file->loadNode((string)$group[0], (string)$type[0]); // group, type
			$nodes[] = new $nodeClass($this->cms, $el); 
		}

		return $nodes;
	}

	function getSXML($tables, $where, cView $view = null)
	{
		$mainTable = array_shift($tables);

		//stránkování
		if ($view->paging!=null) 
		{
			$limit="LIMIT ".$view->paging;
			if ($view->page!=null) 
			{
				//pro stabilitu
				if ($view->page==0) $view->page=1;
				$limit.=" OFFSET ".($view->page-1)*$view->paging;
			}
		} else unset($view->paging);
		
		//viditelnost privátních
		if (is_numeric($aId = $this->cms->user->id) && $view->mode=="backend") {
			$visibility = '('.$mainTable.'.visibility<>\'private\' OR '.$mainTable.'.author_id='.$aId.')';;
		} else $visibility = '1'; //$mainTable.'.visibility<>\'private\'';
		
		//z frontendu nechceme vidět nepublikované
		if ($view->mode === "frontend") {
			$visibility.=' AND '.$mainTable.'.visibility=\'published\'';
		}		
		
		if (count($tables)>0) {
			$join="LEFT JOIN `".strToLower($this->prefix.implode("`,`".$this->prefix,$tables))."` USING (id)";
		}
		
		
		$resource = $this->query($q = "SELECT * FROM `".$this->prefix.$mainTable."` $join WHERE $visibility AND $where $limit");
		//echo $q;
		
		$sxmlArr = $this->mysqlFetchSXML($resource);
		//print_r($sxmlArr);
		
		return $sxmlArr;
	}
	
	/**
	 *	Rozporcuje pole řádku joinnuté v sql dotazu do pole [tabulka][sloupec] = hodnota *	
	 *	$res mysql result, který vrací funkce mysql_query *
 	 */
	function mysqlFetchSXML($resource) 
	{
		$rowNum = 0;
		//	pokud je nějaký výsledek, zjistíme info
		if ($row = mysql_fetch_row($resource)) {
				$numFields = count($row); 
				for ($i=0; $i<$numFields; $i++) 
				{
					//	table's name
					$fInfo[$i][0] = mysql_field_table($resource, $i);
	
					//	fields's name
					$fInfo[$i][1] = mysql_field_name($resource, $i);
					$firstRow = false;
				}	
		} else return array();
		
		do {
			//	sestavíme výstup
			$sxml[$rowNum] = simplexml_load_string('<node />');
			foreach ($row as $i=>$value) 
			{
				$sxml[$rowNum]->{$fInfo[$i][0]}->{$fInfo[$i][1]} = $value;
			}
			$rowNum++;
		} while ($row = mysql_fetch_row($resource));
		return $sxml;
	}	
	
	/* ====================================================== */
	/* ------------------ TRAVERZOVACÍ FUNKCE --------------- */
	/* ====================================================== */
	
	
	/** překouše řádky na adresářovou strukturu */
	function levelizeRows($rows)
	{
		$l=0;
		foreach ($rows as $i=>$n) {
			$rows[$i]["level"]=$l;
			if (($n["rgt"]+1)>$rows[($i+1)]["rgt"]) $l++;
			if ($i==count($rows) && $i>1) 
			{
				if ($l>1) $l--; 
			} else {
				for ($u=$n["rgt"]; ($rows[($i+1)]["lft"]-$u)>1; $u++) { if ($l>1) $l--; }			
			}
		}		
		return $rows;	
	}	
	
	
	function query($q) {
		if ($r=mysql_query($q,$this->cms->link)) {
			return $r;
		} else throw new cException("$q ".mysql_error());
	}
	
	function fixDB() 
	{
		$res = $this->query("SELECT `id`,`parent_id` FROM `".$this->table."` ORDER BY `lft`");
		while ($row = mysql_fetch_array ($res)) 
		{
			$this->tree_rows[(string)$row['parent_id']][]=$row['id']; 
		}
		$this->countLR('NULL',1);
	}

	private function countLR($id_p,$i) 
	{
		if (is_array($this->tree_rows[$id_p])) 
		{
			foreach ($this->tree_rows[$id_p] as $id) 
			{
				$right=$this->countLR($id,($i+1));
				$this->query("UPDATE `".$this->table."` SET `lft`=$i,`rgt`=$right WHERE `id`=".$id);
				$i=$right+1;
			}
		}
    	return $i;
	}

	
}
 
?>